package com.xz.diagnosisOrder.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xz.common.core.domain.model.LoginUser;
import com.xz.common.exception.ServiceException;
import com.xz.common.utils.DateUtils;
import com.xz.common.utils.RedisCode;
import com.xz.common.utils.SecurityUtils;
import com.xz.diagnosis.domain.DiagnosisItem;
import com.xz.diagnosis.domain.DiagnosisPackage;
import com.xz.diagnosis.domain.DiagnosisRegistrationFee;
import com.xz.diagnosis.mapper.DiagnosisRegistrationFeeMapper;
import com.xz.diagnosis.service.IDiagnosisItemService;
import com.xz.diagnosis.service.IDiagnosisPackageService;
import com.xz.diagnosisOrder.domain.DiagnosisOrder;
import com.xz.diagnosisOrder.domain.DiagnosisTreatmentOrder;
import com.xz.diagnosisOrder.dto.DiagnosisTreatmentOrderDetailDto;
import com.xz.diagnosisOrder.dto.DiagnosisTreatmentOrderSaveDto;
import com.xz.diagnosisOrder.enums.ArrivalStatusEnum;
import com.xz.diagnosisOrder.enums.DiagnosisOrderTypeEnum;
import com.xz.diagnosisOrder.enums.PaymentStatusEnum;
import com.xz.diagnosisOrder.enums.TreatmentOrderTypeEnum;
import com.xz.diagnosisOrder.mapper.DiagnosisOrderMapper;
import com.xz.diagnosisOrder.mapper.DiagnosisTreatmentOrderMapper;
import com.xz.diagnosisOrder.service.IDiagnosisTreatmentOrderDetailService;
import com.xz.diagnosisOrder.service.IDiagnosisTreatmentOrderInitService;
import com.xz.diagnosisOrder.service.IDiagnosisTreatmentOrderService;
import com.xz.patient.domain.PatientInfo;
import com.xz.patient.service.IPatientInfoService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 就诊单数据初始化Service业务层处理
 *
 * @author xz
 * @date 2024-03-25
 */
@Service
public class DiagnosisTreatmentOrderInitServiceImpl implements IDiagnosisTreatmentOrderInitService {
  @Autowired
  private IPatientInfoService iPatientInfoService;
  @Autowired
  private DiagnosisOrderMapper diagnosisOrderMapper;
  @Autowired
  private DiagnosisRegistrationFeeMapper diagnosisRegistrationFeeMapper;
  @Autowired
  private IDiagnosisTreatmentOrderDetailService diagnosisTreatmentOrderDetailService;
  @Autowired
  private IDiagnosisPackageService diagnosisPackageService;
  @Autowired
  private IDiagnosisItemService diagnosisItemService;

  /**
   * 初始化主订单数据
   *
   * @param dto
   * @return
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public DiagnosisTreatmentOrder initMainOrder(DiagnosisTreatmentOrderSaveDto dto) {

    DiagnosisOrder diagnosisOrder = diagnosisOrderMapper.selectDiagnosisOrderById(dto.getDiagnosisOrderId());
    if (null == diagnosisOrder || !ArrivalStatusEnum.ARRIVED.eq(diagnosisOrder.getArrivalStatus())) {
      throw new ServiceException("该挂号单当前状态无法开单");
    }

    PatientInfo patient = iPatientInfoService.selectPatientInfoById(diagnosisOrder.getPatientId());
    if (null == patient) {
      throw new ServiceException("该患者信息已失效，无法开单");
    }
    dto.setPatient(patient);
    //声明主订单
    DiagnosisTreatmentOrder mainOrder = new DiagnosisTreatmentOrder();
    // 如果选择了医生，则填充医生信息
    if(null != dto.getRegistrationFeeId()){
      DiagnosisRegistrationFee registrationFee = diagnosisRegistrationFeeMapper.selectDiagnosisRegistrationFeeById(dto.getRegistrationFeeId());
      if (null == registrationFee) {
        throw new ServiceException("该医生数据已失效，请选择其他医生");
      }
      //填充医生信息
      mainOrder.setRegistrationFeeId(registrationFee.getId());
      mainOrder.setDoctorName(registrationFee.getDoctorName());
    }
    mainOrder.setDiagnosisOrderId(dto.getDiagnosisOrderId());
    mainOrder.setOrderType(DiagnosisOrderTypeEnum.MAIN_ORDER.getType());
    mainOrder.setOrderNo(RedisCode.getCode("ZL"));
    //填充预约单信息
    mainOrder.setPatientId(diagnosisOrder.getPatientId());
    mainOrder.setRegistrationDate(diagnosisOrder.getRegistrationDate());
    //填充创建人信息
    LoginUser user = SecurityUtils.getLoginUser();
    mainOrder.setCreateBy(user.getUserId());
    mainOrder.setTenantId(user.getTenantId());
    mainOrder.setDeptId(user.getDeptId());
    mainOrder.setCreateTime(DateUtils.getNowDate());
    //填充支付时间，状态
    mainOrder.setPaymentStatus(PaymentStatusEnum.PAID.getStatus());
    mainOrder.setPaymentTime(DateUtils.getNowDate());
    //填充折扣，减免优惠信息
    mainOrder.setPreferentialAmount(dto.getPreferentialAmount());
    mainOrder.setReduceAmount(dto.getReduceAmount());
    mainOrder.setAfterDiscountAmount(dto.getAfterDiscountAmount());
    //初始化金额相关字段
    mainOrder.setCollectionAmount(dto.getCollectionAmount());
    //填充收银台信息
    mainOrder.setPaymentType(dto.getPaymentType());
    mainOrder.setWalletPay(dto.getWalletPay());
    mainOrder.setPendingAmount(dto.getPendingAmount());
    mainOrder.setMemberCardNo(dto.getMemberCardNo());
    // 备注
    mainOrder.setRemark(dto.getRemark());
    return mainOrder;
  }

  /**
   * 初始化“开单”（子订单）数据
   *
   * @param mainOrder       主订单信息
   * @param orderDetailDtos 子订单dto集合
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public List<DiagnosisTreatmentOrder> initSubOrder(DiagnosisTreatmentOrder mainOrder, List<DiagnosisTreatmentOrderDetailDto> orderDetailDtos) {
    // “开单”数据（子订单）集合
    List<DiagnosisTreatmentOrder> subOrders = new ArrayList<>();
    // 开始根据项目/套餐，分别创建多个“开单”数据放入集合中，并且计算所有子订单的购买数量，金额放入主订单中
    orderDetailDtos.forEach(subOrderDto -> {
      // 初始化子订单数据
      DiagnosisTreatmentOrder subOrder = initSubOrder(mainOrder, subOrderDto);
      // 放入子订单集合中
      subOrders.add(subOrder);
    });
    return subOrders;
  }

  /**
   * 初始化“开单”（子订单）数据
   *
   * @param mainOrder   主订单信息
   * @param subOrderDto 子订单
   * @return
   */
  private DiagnosisTreatmentOrder initSubOrder(DiagnosisTreatmentOrder mainOrder, DiagnosisTreatmentOrderDetailDto subOrderDto) {
    //构建1.套餐，2.项目订单
    DiagnosisTreatmentOrder subOrder = new DiagnosisTreatmentOrder();
    //从主订单中拷贝主要字段信息
    BeanUtils.copyProperties(mainOrder, subOrder);
    // 从dto中拷贝这三项：检查项目/套餐ID, 检查项目/套餐类型, 购买数量
    subOrder.setAssociationId(subOrderDto.getId());
    subOrder.setOrderTitle(subOrderDto.getName());
    subOrder.setOrderType(subOrderDto.getType());
    subOrder.setQuantity(subOrderDto.getQuantity());
    subOrder.setPrice(subOrderDto.getPrice());
    subOrder.setTotalPrice(subOrder.getPrice().multiply(new BigDecimal(subOrder.getQuantity())));

    subOrder.setPreferentialAmount(subOrderDto.getPreferentialAmount());
    subOrder.setReduceAmount(subOrderDto.getReduceAmount());
    subOrder.setAfterDiscountAmount(subOrderDto.getAfterDiscountAmount());
    subOrder.setCollectionAmount(subOrderDto.getCollectionAmount());

    //根据类型，查询对应的（套餐，项目）数据填充。
    if (TreatmentOrderTypeEnum.PACKAGES.eq(subOrder.getOrderType())) {
      //查询套餐，填充套餐对应的字段。
      //DiagnosisPackage diagnosisPackage = diagnosisPackageService.selectDiagnosisPackageById(subOrder.getAssociationId());
      // 填充这三个字段：订单标题，套餐价格，计算总价（套餐价格 * 购买数量）
      //subOrder.setOrderTitle(diagnosisPackage.getPackageName());
      //subOrder.setPrice(diagnosisPackage.getPackagePrice());
      //subOrder.setTotalPrice(subOrder.getPrice().multiply(new BigDecimal(subOrder.getQuantity())));
      //初始化详情数据
      diagnosisTreatmentOrderDetailService.initForPackage(subOrder);

    } else if (TreatmentOrderTypeEnum.ITEMS.eq(subOrder.getOrderType())) {
      //查询项目，填充项目对应的字段。
      DiagnosisItem item = diagnosisItemService.selectDiagnosisItemById(subOrder.getAssociationId());
      // 填充这三个字段：项目单价，计算总价（项目单价 * 购买数量）
      //subOrder.setOrderTitle(item.getItemName());
      //subOrder.setPrice(item.getPrice());
      //subOrder.setTotalPrice(subOrder.getPrice().multiply(new BigDecimal(subOrder.getQuantity())));
      //初始化详情数据
      diagnosisTreatmentOrderDetailService.initForItem(subOrder, item);
    }
    return subOrder;
  }

  /**
   * 计算钱包费用
   *
   * @param mainOrder 主订单
   * @param subOrders 子订单
   */
  @Override
  public void calculateCosts(DiagnosisTreatmentOrder mainOrder, List<DiagnosisTreatmentOrder> subOrders) {

    // 初始化钱包金额
    mainOrder.setWalletPay(mainOrder.getWalletPay() == null ? new BigDecimal(0) : mainOrder.getWalletPay());
    // 待收金额 （收款金额 - 钱包支付金额）
    mainOrder.setPendingAmount(mainOrder.getCollectionAmount().subtract(mainOrder.getWalletPay()));

    //开始计算子订单
    mainOrder.setQuantity(0);
    mainOrder.setTotalPrice(new BigDecimal(0));
    mainOrder.setTotalWalletPay(new BigDecimal(0));
    subOrders.forEach(subOrder -> {
      mainOrder.setQuantity(mainOrder.getQuantity() + subOrder.getQuantity());
      mainOrder.setTotalPrice(mainOrder.getTotalPrice().add(subOrder.getTotalPrice()));


      if (mainOrder.getWalletPay().compareTo(BigDecimal.ZERO) == 0) {
        //钱包支付是0的话，则其他支付等于收款金额
        subOrder.setWalletPay(BigDecimal.ZERO);
        subOrder.setPendingAmount(subOrder.getCollectionAmount());
      }else if (mainOrder.getPendingAmount().compareTo(BigDecimal.ZERO) == 0) {
        //其他支付是0的话，则钱包支付金额等于收款金额
        subOrder.setWalletPay(subOrder.getCollectionAmount());
        subOrder.setPendingAmount(BigDecimal.ZERO);
      }else{
        // 【子订单】金额占比 = 【子订单】收款金额 / 【主订单】收款金额占比
        BigDecimal proportion = subOrder.getCollectionAmount().divide(mainOrder.getCollectionAmount(),2, BigDecimal.ROUND_HALF_UP);
        //【子订单】钱包支付金额 = 【主订单】钱包支付金额 * 【子订单】金额占比
        subOrder.setWalletPay(mainOrder.getWalletPay().multiply(proportion).setScale(2, BigDecimal.ROUND_HALF_UP));
        //【子订单】 待收金额 （【子订单】收款金额 - 【子订单】钱包支付金额）
        subOrder.setPendingAmount(subOrder.getCollectionAmount().subtract(subOrder.getWalletPay()));
      }
    });
  }
}
